package org.vison.wonfu.framework.dao;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageRowBounds;
import org.apache.ibatis.executor.BatchResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;

/**
 * 设计原则：
 * 1. 所有数据库的直接操作都要在dao层完成，抽象类的所有方法都不应该是public的
 * @param <M>
 * @param <T>
 */
public abstract class AbstractDao <M extends AbstractMapper<T>, T extends IPO<Long>>{

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractDao.class);

    @Autowired
    protected M mapper;

    protected PageInfo<T> listPage(int page,int pageSize, LambdaQueryWrapper<T> query){
        PageHelper.startPage(page, pageSize);
        return new PageInfo<>(mapper.selectList(query));
    }

    /**
     * 根据 ID 查询（对应 findById）
     * @param id 主键 ID
     * @return 单个实体或 null
     */
    protected T findById(Long id) {
        return mapper.selectById(id);
    }


    private T findOne(Wrapper<T> query, boolean throwExc){
        if(throwExc){
            return mapper.selectOne(query);
        }else{
            List<T> list = mapper.selectList(query);
            if (!CollectionUtils.isEmpty(list)) {
                int size = list.size();
                if (size > 1) {
                    log.warn("Warn: execute Method There are {} results.", size);
                }
                return list.get(0);
            }
            return null;
        }
    }

    /**
     * 查询所有（对应 listAll）
     * @return 所有实体的列表
     */
    protected List<T> listAll() {
        LambdaQueryWrapper<T> query = new LambdaQueryWrapper<>();
        return mapper.selectList(query);
    }


    protected T findByWrapper(Wrapper<T> query){
        return findOne(query, false);
    }

    protected T findByWrapper(Wrapper<T> query, boolean throwExc){
        return findOne(query, throwExc);
    }



    /**
     * 复杂条件查询（多条件组合，对应 listByXXXAndXXX）
     * 示例：通过 Wrapper 构建 age > 18 and status = 1 等条件
     * @param queryWrapper 条件构造器
     * @return 实体列表
     */
    protected List<T> listByWrapper(Wrapper<T> queryWrapper) {
        return mapper.selectList(queryWrapper);
    }

    /**
     * 统计数量（对应 countByXXX）
     * @return 符合条件的记录数
     */
    protected long countByWrapper(Wrapper<T> queryWrapper) {
        return mapper.selectCount(queryWrapper);
    }

    /**
     * 判断记录是否存在（对应 existsByXXX）
     * @return true：存在；false：不存在
     */
    protected boolean existsBy(Wrapper<T> queryWrapper) {
        return mapper.selectCount(queryWrapper) > 0;
    }


    /**
     * 保存单个实体（新增或更新，对应 save）
     * @param entity 实体对象
     * @return true：操作成功；false：失败
     */
    protected boolean save(T entity) {
        return mapper.insertOrUpdate(entity);
    }

    /**
     * 强制新建（仅新增，主键已存在则抛异常，对应 create）
     * @param entity 实体对象（主键需为 null 或未设置）
     * @return 受影响的行数，通常为 1（新增成功）或抛出异常（主键已存在）
     * @throws IllegalArgumentException 若主键已存在
     */
    protected int create(T entity) {
       return mapper.insert(entity);
    }

    /**
     * 批量新增（对应 createBatch）
     * @param entities 实体集合
     */
    protected List<BatchResult> createBatch(Collection<T> entities) {
        return mapper.insert(entities);
    }


    // ========================== 更新操作（Command）==========================

    /**
     * 全量更新（根据主键更新所有字段，对应 update）
     * @param entity 实体对象（必须包含主键）
     * @return true：更新成功；false：失败（如主键不存在）
     */
    protected int update(T entity) {
        return mapper.updateById(entity);
    }


    // ========================== 删除操作（Command）==========================

    /**
     * 根据 ID 物理删除（对应 deleteById）
     * @param id 主键 ID
     * @return true：删除成功；false：失败
     */
    protected boolean deleteById(Long id) {
        return mapper.deleteById(id) > 0;
    }

    /**
     * 逻辑删除（按 ID 更新逻辑删除标记，对应 removeById）
     * 需配合 MyBatis-Plus 逻辑删除配置（如 @TableLogic 注解）
     * @param id 主键 ID
     * @return true：逻辑删除成功；false：失败
     */
    protected boolean removeById(Long id) {
        // 将 delete 字段置位 1
        T entity = findById(id);
        entity.setDeleted(1);
        return update(entity) > 0;
    }

}
